using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;

namespace Tools.UI.InputEvent
{
    public enum Axis
    {
        Any,
        Horizontal,
        /// <summary>
        ///   <para>Vertical.</para>
        /// </summary>
        Vertical,
    }
    
    [RequireComponent(typeof(RectTransform))][AddComponentMenu("Tools/UI/OnUIDrag")]
    public class OnUIDrag : MonoBehaviour, IPointerDownHandler,IPointerUpHandler,IDragHandler
    {
        [SerializeField][Header("为空时 自动获取父节点")]
        RectTransform anchorRectTransform;

        [SerializeField] [Header("设置位置的RectTransform，为空时，自动获取本节点")]private RectTransform setPositionTrans;

        [SerializeField] private Axis axis;
        
        public RectTransform URectTransform
        {
            get
            {
                if(setPositionTrans == null)
                {
                    setPositionTrans = GetComponent<RectTransform>();
                }
                return setPositionTrans;
            }
        }
        
       
        public  RectTransform UParentRectTransform
        {
            get
            {
                if(anchorRectTransform == null)
                {
                    anchorRectTransform = URectTransform.parent.GetComponent<RectTransform>();
                }
                return anchorRectTransform;
            }
        }
        
        [SerializeField]
        UnityEvent<OnUIDrag,PointerEventData> onDragReady = new UnityEvent<OnUIDrag,PointerEventData>();
        public UnityEvent<OnUIDrag,PointerEventData> OnDragReady => onDragReady;
        
        [SerializeField]
        UnityEvent<OnUIDrag,PointerEventData> onDragEnd = new UnityEvent<OnUIDrag,PointerEventData>();
        public UnityEvent<OnUIDrag,PointerEventData> OnDragEnd => onDragEnd;
        
        [SerializeField]
        UnityEvent<OnUIDrag,PointerEventData>onDragging = new UnityEvent<OnUIDrag,PointerEventData>();
        public UnityEvent<OnUIDrag,PointerEventData> OnDragging => onDragging;

        private void Start()
        {
            
        }

        private bool downIs;
        private int downPointId;
        
        private Vector2 _downLocalPosition;
        private Vector2 _downAnchorPosition;
        private Vector2 _startOffset;

        public Axis CurrentAxis
        {
            get => axis;
            set
            {
                axis = value;
                UpdateStartOffset();
            }
        }

        void UpdateStartOffset()
        {
            Vector2 tempLocalPosition = _downLocalPosition;
            if(axis != Axis.Horizontal && axis!= Axis.Any)
            {
                tempLocalPosition.x = 0;
            }
            else if(axis != Axis.Vertical && axis!= Axis.Any)
            {
                tempLocalPosition.y = 0;
            }
            _startOffset = _downAnchorPosition - tempLocalPosition;
        }
        
        void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
        {
            if (!enabled) return;
            if (downIs) return;
            downIs = true;
            downPointId = eventData.pointerId;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                UParentRectTransform,eventData.position,
                eventData.pressEventCamera,out _downLocalPosition);
            _downAnchorPosition = URectTransform.anchoredPosition;
            UpdateStartOffset();
            OnDragReady?.Invoke(this,eventData);
        }

        void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
        {
            if (!enabled) return;
            if(downIs && downPointId == eventData.pointerId)
            {
                downIs = false;
                OnDragEnd?.Invoke(this,eventData);
            }
        }

        void IDragHandler.OnDrag(PointerEventData eventData)
        {
            if (!enabled) return;
            if (downIs && downPointId == eventData.pointerId)
            {
                RectTransformUtility.ScreenPointToLocalPointInRectangle(UParentRectTransform,eventData.position,eventData.pressEventCamera,out Vector2 localPoint);
                if(axis != Axis.Horizontal && axis!= Axis.Any)
                {
                    localPoint.x = 0;
                }
                else if(axis != Axis.Vertical && axis!= Axis.Any)
                {
                    localPoint.y = 0;
                }
                URectTransform.anchoredPosition = localPoint + _startOffset;
                OnDragging?.Invoke(this,eventData);
            }
        }
    }
}
